home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Skunkware 5
/
Skunkware 5.iso
/
src
/
X11
/
wais
/
waisgate
/
sockets.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-05-09
|
8KB
|
329 lines
/* WIDE AREA INFORMATION SERVER SOFTWARE
No guarantees or restrictions. See the readme file for the full standard
disclaimer.
5.29.90 Harry Morris, morris@think.com
*/
#ifndef lint
static char *RCSid = "$Header: /tmp_mnt/net/quake/proj/wais/wais-8-b5/ir/RCS/sockets.c,v 1.23 92/05/06 17:34:41 jonathan Exp $";
#endif
/* Change log:
* $Log: sockets.c,v $
* Revision 1.23 92/05/06 17:34:41 jonathan
* Added Mach to some compiler switches.
*
* Revision 1.22 92/04/28 15:21:14 jonathan
* Added decoding of IP address to DNS name in accept_client handler.
*
* Revision 1.21 92/04/01 09:49:49 morris
* declared clr_socket static to stop gcc from complaining
*
* Revision 1.20 92/03/24 10:35:32 jonathan
* Put a loop around connect in fd_connect_to_server to check if the connect
* was interrupted by a system call (usually a timer). Retries if errno is
* EINTR.
*
* Revision 1.19 92/02/16 12:38:22 jonathan
* Changed bzero's to memset's.
*
* Revision 1.18 92/02/16 12:34:11 jonathan
* Removed code refering to NOINETNTOA, since we should use inet_ntoa.
*
* Revision 1.17 92/02/12 13:48:21 jonathan
* Added "$Log" so RCS will put the log message in the header
*
*
*/
/*
Added code in fd_accept_client_connection to print source Inet address to
stderr.
- Jonny G Fri Apr 12 1991
*/
#define sockets_c
#include "sockets.h"
#ifdef NOTCPIP /* we don't have TCPIP */
void open_server (port,socket,size) long port; long* socket; long size; {}
void accept_client_connection (socket,file) long socket; FILE** file; {}
void close_client_connection (file) FILE* file; {}
void close_server (socket) long socket; {}
FILE *connect_to_server (host_name,port) char* host_name; long port;
{return(NULL);}
void close_connection_to_server (file) FILE* file; {}
#else /* there is TCPIP */
#include <errno.h>
#include <string.h>
#include "panic.h"
#if (defined(ultrix) || defined(BSD) || defined(Mach))
extern int errno;
#endif /* ultrix BSD or Mach */
extern char *sys_errlist[];
/* XXX
still need:
non-blocking modes
special send/recieve functions? (there are now some in ui.c)
asynchronous calls?
*/
/* define the number of queued connections allowable on each port */
#define QUEUE_SIZE 3
/*---------------------------------------------------------------------------*/
/* Server functions */
/*---------------------------------------------------------------------------*/
static boolean clr_socket _AP((struct sockaddr_in *address, long portnumber,
long* sock));
static boolean clr_socket(address, portnumber, sock)
struct sockaddr_in *address;
long portnumber;
long *sock;
{
if (errno == EADDRINUSE) {
/* Try connecting to it */
if (connect(*sock, address, sizeof (struct sockaddr_in)) == 0) {
close(*sock);
waislog(WLOG_HIGH, WLOG_ERROR,
"Cannot bind port %ld: (Address already in use).",
portnumber);
waislog(WLOG_HIGH, WLOG_ERROR, "waisserver is already running on this system");
panic("Exiting");
} else {
/* Connection failed; probably socket in FIN_WAIT */
int one = 1;
(void) close(*sock);
if ((*sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
panic("Open socket failed in trying to clear the port.");
/*printf("Error binding port %d: (address already in use).\n\
Attempting to clear stale socket...", portnumber);*/
if ( setsockopt(*sock, SOL_SOCKET, SO_REUSEADDR,
&one, sizeof (one)) < 0) {
/*printf("Warning: Setsockopt SO_REUSEADDR failed.");*/
}
address->sin_family = AF_INET;
address->sin_addr.s_addr = INADDR_ANY;
address->sin_port = htons(portnumber);
if (bind(*sock, address, sizeof(*address)) == 0) {
/*printf("Successfully cleared stale EADDRINUSE error");*/
}
}
}
return(true);
}
void
open_server(port,fd,size)
long port;
long* fd;
long size;
{ struct sockaddr_in address;
memset(&address, 0, sizeof(address));
/* open the fd */
if ((*fd = socket(AF_INET,SOCK_STREAM,0)) < 0){
panic("can't get file descriptor for socket: %s", sys_errlist[errno]);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = htonl(INADDR_ANY);
address.sin_port = htons(port);
if (bind(*fd,(struct sockaddr*)&address,sizeof(struct sockaddr)) < 0)
clr_socket(&address, port, fd);
if (listen(*fd,QUEUE_SIZE) < 0)
panic("can't open server: %s", sys_errlist[errno]);
}
/* This is a lower level function provided for use by the lisp version of
* this library
* XXX should support non-blocking mode
*/
#include <arpa/inet.h>
void
fd_accept_client_connection(socket,fd)
long socket;
long* fd;
{ /* accept an input connection, and open a file on it */
struct sockaddr_in source;
int sourcelen;
#ifdef BSD
struct in_addr {
union {
struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
u_long S_addr;
} S_un;
} addr_p;
#endif /* BSD */
sourcelen = sizeof(struct sockaddr_in);
do {
errno = 0;
*fd = accept(socket, &source, &sourcelen);
} while (*fd < 0 && errno == EINTR);
if(source.sin_family == AF_INET) {
struct hostent *peer = NULL;
peer = gethostbyaddr(&source.sin_addr, 4, AF_INET);
waislog(WLOG_MEDIUM, WLOG_CONNECT,
"Accepted connection from: %s [%s]",
peer->h_name,
#if defined(sparc) && defined(__GNUC__)
inet_ntoa(&source.sin_addr)
#else
inet_ntoa(source.sin_addr)
#endif /* sparc */
);
}
if (*fd < 0)
panic("can't accept connection");
}
/* This is the prefered C function for accepting client requests */
void
accept_client_connection(socket,file)
long socket;
FILE** file;
{ long fd; /* file descriptor actually used */
fd_accept_client_connection(socket,&fd);
if ((*file = fdopen(fd,"r+")) == NULL)
panic("can't accept connection");
}
/* When a server wants to end the session with a client */
void
close_client_connection(file)
FILE* file;
{
fclose(file);
}
/* when exiting the top level server process (not the forked
server processes that come one per client).
Maybe we need to do this once per client as well.
*/
void
close_server(socket)
long socket;
{
close(socket);
}
/*---------------------------------------------------------------------------*/
/* Client functions */
/*---------------------------------------------------------------------------*/
/* This is a lower level function provided for use by the lisp version of
* this library
* XXX should support non-blocking mode
*/
#define HOSTNAME_BUFFER_SIZE 120
#define MAX_RETRYS 10
boolean
fd_connect_to_server(host_name,port,fd)
char* host_name;
long port;
long* fd;
{
char hostnamebuf[80];
long rc, i;
struct hostent *host;
/* struct servent *service = NULL; not used */
struct sockaddr_in name;
memset((char *)&name, 0,sizeof (name));
name.sin_addr.s_addr = inet_addr(host_name);
if (name.sin_addr.s_addr != -1) {
name.sin_family = AF_INET;
(void) strcpy(hostnamebuf, host_name);
}
else {
host = gethostbyname(host_name);
if(NULL == host){
return FALSE;
}
name.sin_family = host->h_addrtype;
#ifdef h_addr
bcopy(host->h_addr_list[0],
(caddr_t)&name.sin_addr, host->h_length);
#endif
(void) strcpy(hostnamebuf, host->h_name);
}
host_name = hostnamebuf;
name.sin_port = htons(port);
*fd = socket (AF_INET, SOCK_STREAM, 0);
for(i = 0; i < MAX_RETRYS; i++) {
rc = connect (*fd, &name, sizeof (name));
if(rc == 0) return TRUE;
else if(errno == EINTR){
sleep(1);
}
else {
perror("Connect to socket did not work (1)");
return FALSE;
}
}
return FALSE;
}
/* This is the prefered C function for initiating client requests */
FILE *
connect_to_server(host_name,port)
char* host_name;
long port;
{
FILE* file;
long fd;
if(fd_connect_to_server(host_name,port,&fd) == FALSE) {
perror("Connect to socket did not work (2)");
return NULL;
}
if ((file = fdopen(fd,"r+")) == NULL) {
perror("Connect to socket did not work (3)");
return NULL;
}
return file;
}
void
close_connection_to_server(file)
FILE* file;
{
fclose(file);
}
/*---------------------------------------------------------------------------*/
#endif /* there is TCPIP */